비정상 종료 시그널 종류 — SIGSEGV·SIGABRT·SIGBUS·SIGILL·SIGFPE 개관
NOTE
“Segmentation fault (core dumped)” 한 줄만 보고는 원인을 알 수 없다. 이 시리즈는 “무슨 시그널로 죽었는지 식별 → 그 시그널이 왜 발생하는지 원인 후보 좁히기 → core dump로 실제 증거 확보” 3단계로 비정상 종료를 분석하는 방법을 정리한다.
0. 정상 종료 vs 비정상 종료
프로세스가 끝나는 방법은 두 가지뿐이다.
| 구분 | 방법 | 셸에서 보이는 것 | waitpid 판별 |
|---|---|---|---|
| 정상 종료 | exit()/return으로 종료 코드 반환 | 에러 없이 프롬프트로 복귀 | WIFEXITED(status) true |
| 비정상 종료 | 처리 안 된 시그널에 의해 강제 종료 | Segmentation fault, Aborted 등 메시지 | WIFSIGNALED(status) true |
부모 프로세스(셸 포함)는 waitpid()로 자식의 종료 상태를 받는데, 이때 어떤 시그널로 죽었는지, core를 남겼는지까지 다 알 수 있다.
#include <sys/wait.h>
int status;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
printf("정상 종료, 코드=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("시그널 %d(%s)로 종료, core dump=%s\n",
WTERMSIG(status), strsignal(WTERMSIG(status)),
WCOREDUMP(status) ? "생성됨" : "없음");
}1. 셸의 $? — 128 + 시그널 번호 규칙
bash에서 방금 실행한 프로세스의 종료 상태를 확인하면:
$ ./a.out
Segmentation fault (core dumped)
$ echo $?
139139 = 128 + 11(SIGSEGV). 셸은 시그널로 죽은 프로세스의 종료 코드를 128 + 시그널번호로 표현한다. 역산하면 로그에 코드만 남아 있어도 어떤 시그널이었는지 바로 알 수 있다.
$? | 128 + N | 시그널 |
|---|---|---|
| 132 | 128+4 | SIGILL |
| 134 | 128+6 | SIGABRT |
| 136 | 128+8 | SIGFPE |
| 137 | 128+9 | SIGKILL (OOM killer 등 강제종료 의심) |
| 138 | 128+10 | SIGBUS (일부 아키텍처) |
| 139 | 128+11 | SIGSEGV |
| 141 | 128+13 | SIGPIPE |
TIP
137(SIGKILL)이 보이는데 코드에 짚이는 게 없다면 크래시가 아니라 OOM killer에게 강제로 죽었을 가능성이 높다.
dmesg | grep -i "killed process"로 확인한다 — 자세한 건 4. 추가로 알아야 할 것들 참고.
2. 시그널 기본 동작(disposition)
핸들러를 따로 안 걸면 커널이 시그널마다 정해진 기본 동작을 한다.
| 기본 동작 | 의미 |
|---|---|
| Term | 프로세스 종료 (core 없음) |
| Core | 프로세스 종료 + core dump 파일 생성 |
| Ign | 무시 |
| Stop / Cont | 일시정지 / 재개 |
비정상 종료 분석 대상은 기본 동작이 Core인 시그널들이다.
3. 비정상 종료를 일으키는 주요 시그널 표
| 시그널 | 번호(x86_64 Linux) | 기본동작 | 한 줄 요약 |
|---|---|---|---|
SIGILL | 4 | Core | 잘못된/실행 불가능한 명령어 실행 |
SIGABRT | 6 | Core | abort() 호출 — assert 실패, 힙 손상 탐지 등 프로그램이 “스스로” 중단 |
SIGFPE | 8 | Core | 산술 오류 — 정수 0으로 나누기 등 (이름과 달리 부동소수점 전용 아님) |
SIGBUS | 7 | Core | 정렬 안 된 접근, mmap 범위 밖 접근 등 하드웨어 레벨 버스 오류 |
SIGSEGV | 11 | Core | 매핑 안 되었거나 권한 없는 메모리 접근 (가장 흔한 크래시) |
SIGSYS | 31 | Core | 허용 안 된 시스템 콜 호출 (seccomp 등) |
SIGXCPU | 24 | Core | CPU 시간 제한 초과 |
SIGXFSZ | 25 | Core | 파일 크기 제한 초과 |
SIGQUIT | 3 | Core | 터미널에서 Ctrl+\ — 사용자가 직접 core 요청 |
SIGKILL | 9 | Term (core 없음) | 차단·무시 불가. OOM killer, kill -9 |
SIGPIPE | 13 | Term (core 없음) | 닫힌 파이프/소켓에 write |
SIGTERM | 15 | Term (core 없음) | 정상적인 종료 요청 (graceful shutdown 대상) |
이 중 실무에서 원인 분석이 필요한 5대 시그널은 SIGSEGV, SIGABRT, SIGBUS, SIGILL, SIGFPE다. 각각이 왜 발생하는지는 2. 시그널별 원인 분석에서 다룬다.
4. “core dumped”인데 core 파일이 없다면
메시지에 (core dumped)가 찍혔다고 항상 core 파일이 남는 건 아니다. ulimit -c가 0이면 커널이 core 생성을 아예 시도하지 않고, 일부 환경은 시도하다 실패해도 메시지만 그대로 남긴다. core dump를 실제로 남기고 분석하는 방법은 3. Core Dump 확인 방법에서 다룬다.
관련 문서
- 2. 시그널별 원인 분석 — 각 시그널이 실제로 왜 발생하는가
- 3. Core Dump 확인 방법 — 활성화·수집·gdb 분석
- 4. 추가로 알아야 할 것들 — dmesg·siginfo_t·ASan·예방 도구
- [C] 리눅스 시스템 함수(System Call) 카테고리별 치트시트 —
sigaction/kill/raise등 시그널 제어 함수